`timescale 1ns/10ps 

module tb ;
  
  
reg clk ;
reg rst_n ;
reg rs_clk_11p52 ;
reg rs_clk_1p152 ;
reg rs_clk_p1152 ;

initial begin 
clk = 0 ;
rs_clk_11p52 = 1'b0;
rs_clk_1p152 = 1'b0 ;

#100 rs_clk_p1152 = 1'b0 ;
rst_n = 0 ;
repeat(4) @(posedge rs_clk_p1152) ;
rst_n = 1 ;

end

 always #5 clk=~clk ; 
 always #43.4 rs_clk_11p52=~rs_clk_11p52 ; 
 always #434  rs_clk_1p152=~rs_clk_1p152 ; 
 always #4340 rs_clk_p1152=~rs_clk_p1152 ; 
 
 reg RX ;
 reg sys_sta ;
 reg [47:0] ssd_addr ;
 wire [7:0] led ;
 wire [127:0] rs_record_file_name ;
 wire star_record ;
 wire stop_record ;
 wire TX ;
 
 
 reg [7:0] cnt_11p52 ;
 reg [7:0] s_tx ;
 reg       start_bit ;
 reg       rx_valid_bit ;
 integer   frame_type ;
// always @(posedge rs_clk_11p52 or negedge rst_n) begin
//    if(!rst_n) begin
//    	cnt_11p52 <= 8'h0 ;
//    end
//    else if(cnt_11p52=='d99) begin
//    	 cnt_11p52 
//    end
// end
 
 initial  begin
 	RX = 1'b1 ;
 	sys_sta = 1'b1 ;
 	ssd_addr= 48'h0 ;
 	start_bit = 1'b0 ;

 	repeat(10) @(posedge rs_clk_p1152) ;
 	
// 	while(1) begin
     send_frame(8'h00);
     repeat(1000) @(posedge rs_clk_p1152) ;
     send_frame(8'h01);
     repeat(1000) @(posedge rs_clk_p1152) ;
     send_frame(8'h04);
     repeat(1000) @(posedge rs_clk_p1152) ;
     send_frame(8'h01);
     $stop();
 #497990000;  
 repeat(1) @(posedge rs_clk_p1152) ;  
 send_frame(8'h01);
 repeat(1000) @(posedge rs_clk_p1152) ;
 
// 
// while(1) begin
// 	  repeat(10000) @(posedge rs_clk_p1152) ;
// 		send_frame(8'h03);
// end
 	//s_tx = 'h55;
 	//send_rs422(s_tx) ;
//	end

while(1) begin
	 frame_type  = $urandom_range(0,4) ;
	 if(frame_type == 0)	 begin
	 		send_frame(8'h00);
	 		repeat(58600*2) @(posedge rs_clk_p1152) ;
	 end	
	 if(frame_type == 1) begin
	 		send_frame(8'h01);
	 		repeat(10000) @(posedge rs_clk_p1152) ;
	 end
	 if(frame_type == 2) begin
	 	  send_frame(8'h03);
	 	  repeat(10000) @(posedge rs_clk_p1152) ;
	 end
	 if(frame_type == 3) begin
	 	  send_frame(8'h04);
	 	  repeat(10000) @(posedge rs_clk_p1152) ;
	 end
	 	repeat(1) @(posedge rs_clk_p1152) ;	
end

repeat(1000000) @(posedge rs_clk_p1152) ;
 	$stop();
end

initial begin
		@(posedge rst_n) ;
		receive_frame();
end

initial begin
	 @(posedge rst_n) ;
	 wait(tb.u_rs422.inst_data_in.com_err === 1'b1 );
	 repeat(3000000) @(posedge rs_clk_p1152) ;
$stop();
end

initial begin

	@(posedge rst_n) ;
	while(1) begin
	   repeat(10000) @(posedge rs_clk_p1152) begin 
		    ssd_addr = {$random,$random};
	   end
  end
end
  
  RS422_top u_rs422( 
        .clk          (rs_clk_11p52),
        .rst           (!rst_n), 
        .RX            (RX),
        .sys_sta        (sys_sta) ,
        .ssd_addr       (ssd_addr) ,
        .led            (led) ,
        .star_record     (star_record) ,
        .stop_record     (stop_record) ,
        .rs_record_file_name (rs_record_file_name),
        .TX             (TX)
  );

task send_frame(input logic [7:0] ctrl_byte) ;


reg[7:0] head_frame_0 = 8'h10 ;
reg[7:0] head_frame_1 = 8'h01 ;
reg[7:0] length_frame_0 ;
reg[7:0] length_frame_1 ;
reg[7:0] ctrl_frame ;
reg[127:0] file_frame ;
reg[63:0] reserve_frame ;
reg[7:0] sum_frame = 'd00;
reg[7:0] tail_frame_0 = 8'h10 ;
reg[7:0] tail_frame_1 = 8'h03 ;

 reg [31:0] length_rand ;

length_rand = $random();

length_frame_0 = length_rand[7:0] ;
length_frame_1 = length_rand[15:8] ;

//$display("the length_frame_0 = %d !",length_frame_0) ;

//if(length_frame_0 > 'd200) begin
//	 ctrl_frame = 8'h03 ;
//end
//else begin
//		if(length_frame_0 > 'd100) begin
//			ctrl_frame = 8'h00 ;
//	  end
//	  else begin
//	  	ctrl_frame = 8'h01 ;
//	  end
//end
	ctrl_frame = ctrl_byte ;
//if(length_frame_0>=0) begin ctrl_frame = 8'h00 ; end
//else if(200>length_frame_0>=100) begin ctrl_frame = 8'h01 ; end 
//else if(256>length_frame_0>=200) begin ctrl_frame = 8'h03 ; end 
//else begin
//$display();
//end

file_frame = {length_rand,length_rand,length_rand,length_rand} ;
reserve_frame = 63'h0;

//ctrl_frame = 8'h04 ;
//$display("the length_frame_0 = %d ctrl_frame = %d !",length_frame_0,ctrl_frame);
//$display("the length_rand = %h !",length_rand);
send_rs422(head_frame_0);
send_rs422(head_frame_1);
send_rs422(length_frame_0);
send_rs422(length_frame_1);
send_rs422(ctrl_frame);

repeat(16) begin 
	 send_rs422(file_frame[7:0]) ;
end
sum_frame = file_frame[7:0]*16 + ctrl_frame + length_frame_1 +length_frame_0 + head_frame_1 + head_frame_0 ;
repeat(8) begin 
	 send_rs422(reserve_frame[7:0]) ;
end
send_rs422(sum_frame);
send_rs422(tail_frame_0);
send_rs422(tail_frame_1);

endtask

task send_rs422(input reg [7:0] tx_byte) ;
 // input [7:0] tx_byte ;
  //repeat (1) @(posedge rs_clk_p1152) ;
  start_bit = 1'b1 ;
  RX = 1'b0 ;
  for(int i=0;i<8;i++) begin
     @(posedge rs_clk_p1152) ;
     RX = tx_byte[i] ;
  end 
  @(posedge rs_clk_p1152) ;
  RX = 1'b1 ;
  start_bit = 1'b0 ;
//  stop_bit = 1'b1 ;
  @(posedge rs_clk_p1152) ;
  
endtask
  
  
task receive_frame();

//reg [7:0] receive_queue[$] ;
reg[7:0] receive_byte ;
reg[7:0] receive_byte_i ;

while(1) begin
	 receive_rs422(receive_byte) ;
//	 receive_queue.push_back(receive_byte); 
	 $display("%h ",receive_byte);
	 if((receive_byte=='h03)&&(receive_byte_i=='h10)) begin
	 		$display("--------------------\n\n");
	 end
	 receive_byte_i = receive_byte ;
end	


endtask

task receive_rs422(output reg [7:0] rx_byte) ;


   @(negedge TX) ;
   repeat(10) @(posedge rs_clk_1p152) ;
   rx_valid_bit = 1'b1 ;
   for(int i=0;i<8;i++) begin
   	 repeat(5) @(posedge rs_clk_1p152) ;
     rx_byte[i] = TX ;
     repeat(5) @(posedge rs_clk_1p152) ;
  end 
  rx_valid_bit = 1'b0 ;
  repeat(5) @(posedge rs_clk_1p152) ;
  if(TX) begin 
  end
  else begin
			$display("the STOP bit ERROR !");
			repeat (300) @(posedge rs_clk_1p152) ;
			$stop() ;
	end
  repeat(4) @(posedge rs_clk_1p152) ;
endtask 

endmodule 